package com.smartcruise.service;

import android.util.Log;

import com.google.gson.Gson;
import com.smartcruise.MyApplication;
import com.smartcruise.data.SavedLocation;
import com.smartcruise.util.TempleUser;
import com.smartcruise.util.network.callBack.BaseCallBack;
import com.smartcruise.util.network.netUtils.NetCollection;
import com.smartcruise.util.network.netUtils.Result;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.realm.Realm;
import io.realm.RealmResults;

/**
 * Created by FengChaoQun
 * on 2018/2/6 0006
 * 定时上传本地存储的地址
 */

public class UpLoadLocationManager {

    private Realm realm;
    private boolean isUploading;//标记是否正在上传
    private static final int maxItemInOnePost = 500;//一次最多能上传的数据数目
    private static final int intervalTime = 60;//心跳间隔 既检查本地数据的间隔
    private Disposable disposable;
    private RealmResults<SavedLocation> all;
    private BaseCallBack callBack;

    private static class InstanceHolder {

        private static UpLoadLocationManager instance = new UpLoadLocationManager(MyApplication.getInstance().getRealm());

    }

    public static UpLoadLocationManager getInstance() {
        return InstanceHolder.instance;
    }

    private UpLoadLocationManager(Realm realm) {
        this.realm = realm;
    }

    /**
     * description:开始周期性的检查本地数据并上传数据
     */

    public void start() {
        if (disposable == null) {
            disposable = Observable.interval(intervalTime, TimeUnit.SECONDS)
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Consumer<Long>() {
                        @Override
                        public void accept(Long aLong) {
                            doTask();
                        }
                    }, new Consumer<Throwable>() {
                        @Override
                        public void accept(Throwable throwable) {
                            throwable.printStackTrace();
                        }
                    });
        }

        if (all == null) {
            all = realm.where(SavedLocation.class).equalTo("employeeUserId", TempleUser.getInstance().getAccount()).findAll();
        }
    }

    /**
     * description:结束轮询
     */

    public void destroy() {
        if (disposable != null) {
            disposable.dispose();
        }
    }

    /**
     * description:执行上传任务
     */

    private void doTask() {
        if (!isUploading) {
            try {
                upLoadLocalData();
            } catch (Exception e) {//出现异常的时候 要将isUploading设置为false 方便下次轮询的时候继续执行上传操作
                e.printStackTrace();
                isUploading = false;
            }
        }
    }

    private void upLoadLocalData() {
        if (all.isEmpty()) {//本地没有数据 则不执行下一步
            isUploading = false;
            if (callBack != null) {
                callBack.onSuccess(null);
            }
            Log.d("UpLoadLocationManager", "本地坐标已经全部上传完成");
            setCallBack(null);//上传成功后清除回调
            return;
        }
        //如果本地数据少于500 则一次性上传
        if (all.size() < maxItemInOnePost) {
            uploadAll();
        } else {
            upload500Item();
        }
    }

    /**
     * description:手动上传本地坐标 并设置回调
     */

    public void upLoadLocalData(BaseCallBack callBack) {
        Log.d("UpLoadLocationManager", "手动上传坐标 开始...");
        if (isUploading()) {
            Result result = new Result();
            result.setMessage("正在上传本地坐标数据,请稍后再试");
            callBack.onFail(result);
            Log.d("UpLoadLocationManager", "当前正在上传坐标,稍后再试");
            return;
        }
        setCallBack(callBack);
        upLoadLocalData();
    }

    /**
     * description:一次性上传所有数据
     */

    private void uploadAll() {
        //gson序列化的时候 要将数据从数据库中拷贝出来 否则会报错
        List<SavedLocation> savedLocations = new ArrayList<>();
        for (SavedLocation savedLocation : all) {
            if (savedLocation != null && savedLocation.isValid()) {
                savedLocations.add(realm.copyFromRealm(savedLocation));
            }
        }
        Gson gson = new Gson();
        String data = gson.toJson(savedLocations);
        isUploading = true;
        NetCollection.pushLocations(data, new BaseCallBack() {
            @Override
            public void onSuccess(Result result) {
                //上传完成 删除本地数据
                realm.executeTransaction(new Realm.Transaction() {
                    @Override
                    public void execute(Realm realm) {
                        all.deleteAllFromRealm();
                    }
                });
                isUploading = false;

                if (callBack != null) {
                    callBack.onSuccess(null);
                }
                setCallBack(null);//上传成功后清除回调
                Log.d("UpLoadLocationManager", "一次性上传成功");
            }

            @Override
            public void onFail(Result result) {
                isUploading = false;
                if (callBack != null) {
                    callBack.onFail(result);
                }
            }

            @Override
            public void onError(Throwable e) {
                isUploading = false;
                if (callBack != null) {
                    callBack.onError(e);
                }
            }
        });
    }

    /**
     * description:上传前五百个本地数据
     */

    private void upload500Item() {
        final List<SavedLocation> oriData = new ArrayList<>();//保存数据库中的数据 方便上传成功后删除
        final List<SavedLocation> savedLocations = new ArrayList<>();//保存从数据中复制出来的数据 用于序列化
        for (int i = 0; i < maxItemInOnePost; i++) {
            savedLocations.add(realm.copyFromRealm(all.get(i)));
            oriData.add(all.get(i));
        }
        Gson gson = new Gson();
        String data = gson.toJson(savedLocations);
        isUploading = true;
        NetCollection.pushLocations(data, new BaseCallBack() {
            @Override
            public void onSuccess(Result result) {
                //上传完成 删除本地数据
                realm.executeTransaction(new Realm.Transaction() {
                    @Override
                    public void execute(Realm realm) {
                        for (SavedLocation savedLocation : oriData) {
                            savedLocation.deleteFromRealm();
                        }
                    }
                });

                Log.d("UpLoadLocationManager", "分批上传成功");
                //上传前500个数据成功后 继续上传后面的数据
                upLoadLocalData();
            }

            @Override
            public void onFail(Result result) {
                isUploading = false;
                if (callBack != null) {
                    callBack.onFail(result);
                }
            }

            @Override
            public void onError(Throwable e) {
                isUploading = false;
                if (callBack != null) {
                    callBack.onError(e);
                }
            }
        });
    }

    public void setCallBack(BaseCallBack callBack) {
        this.callBack = callBack;
    }

    public boolean isUploading() {
        return isUploading;
    }
}
